#include "graphic_particle_manager.h"

// .. REFERENCES

#include "primitives.h"
#include "graphic_particle_displayer_2d.h"
#include "graphic_particle_emitter_point.h"
#include "graphic_particle_modifier_gravity.h"
#include "graphic_particle_modifier_position.h"
#include "graphic_particle_modifier_life.h"
#include "graphic_particle_modifier_orientation.h"
#include "math_angle.h"

// -- PUBLIC

// .. CONSTRUCTORS

GRAPHIC_PARTICLE_MANAGER::GRAPHIC_PARTICLE_MANAGER() :
    OBJECT(),
    ParticleSystemTable()
{
}

// .. OPERATIONS

GRAPHIC_PARTICLE_SYSTEM::REF GRAPHIC_PARTICLE_MANAGER::CreateEmptySystem()
{
    GRAPHIC_PARTICLE_SYSTEM::REF
        system;

    system.New();

    ParticleSystemTable.Add( system );

    return system;
}

// ~~

GRAPHIC_PARTICLE_SYSTEM::REF GRAPHIC_PARTICLE_MANAGER::CreateConeSystem()
{
    GRAPHIC_PARTICLE_SYSTEM::REF
        system;
    GRAPHIC_PARTICLE_EMITTER_POINT::REF
        emitter;
    GRAPHIC_PARTICLE_MODIFIER_GRAVITY::REF
        modifier_gravity;
    GRAPHIC_PARTICLE_MODIFIER_POSITION::REF
        modifier_position;
    GRAPHIC_PARTICLE_MODIFIER_LIFE::REF
    	modifier_life;
    GRAPHIC_PARTICLE_MODIFIER_ORIENTATION::REF
        modifier_orientation;
    GRAPHIC_PARTICLE_DISPLAYER_2D::REF
    	displayer;

    system.New();
    emitter.New();
    modifier_gravity.New();
    modifier_position.New();
    modifier_life.New();
    modifier_orientation.New();
    displayer.New();

    emitter->AddPosition( MATH_VECTOR_3( 0.0f, 0.0f, 0.0f ) );
    emitter->AddDirection(  MATH_VECTOR_3( 0.0f, 1.0f, 0.0f ) );
    emitter->AddDirectionAngleVariation( 10.0f );
    emitter->AddVelocity( 50.0f );
    emitter->AddVelocity( 10.0f, 0.5f );
    emitter->AddVelocityVariation( 15.0f );

    emitter->AddAngle( -MATH_ANGLE_180Degrees );
    emitter->AddAngleVariation( MATH_ANGLE_360Degrees );
    emitter->AddEmitCount( 30.0f );
    emitter->AddLifeTime( 100.1f );
    emitter->AddSpin( 10.0f );
    emitter->AddSpinVariation( 10.0f );

    emitter->AddExtent( MATH_VECTOR_2( 160.0f, 160.0f ) );
    emitter->AddExtent( MATH_VECTOR_2( 16.0f, 16.0f ) , 0.1f );
    emitter->AddExtentVariation( MATH_VECTOR_2( 16.0f, 16.0f ) );


    emitter->SetRate( 20 );
    emitter->SetDuration( 10.0f );


    modifier_gravity->SetGravity( 1.0f );

    system->SetEmitter( emitter );
    system->SetDisplayer( displayer );

    system->AddModifier( modifier_life );
    system->AddModifier( modifier_gravity );
    system->AddModifier( modifier_position );
    system->AddModifier( modifier_orientation );

    ParticleSystemTable.Add( system );

    return system;
}

// ~~

VOID GRAPHIC_PARTICLE_MANAGER::AddSystem(
    const GRAPHIC_PARTICLE_SYSTEM & system
    )
{
    ParticleSystemTable.Add( &system );
}

// ~~

VOID GRAPHIC_PARTICLE_MANAGER::Update(
    const TIMER & time_step
    )
{   
    INDEX
        system_index;

    for_each_table_index( system_index, ParticleSystemTable )
    {
        ParticleSystemTable[ system_index ]->Update( time_step );
    }
}

// ~~

VOID GRAPHIC_PARTICLE_MANAGER::Render()
{
    INDEX
        system_index;

    for_each_table_index( system_index, ParticleSystemTable )
    {
        ParticleSystemTable[ system_index ]->Render();
    }
}

// .. FUNCTIONS

IMPLEMENT_SINGLETON( GRAPHIC_PARTICLE_MANAGER );

